package GameServer;

import Library.ErrorCodes;
import Library.Game.*;
import java.rmi.*;
import java.rmi.server.UnicastRemoteObject;
import java.util.*;
import java.util.Map.*;

/**
 * Session
 * Met een sessie-object kunnen acties op de gameserver worden uitgevoerd 
 * voor een specifieke speler.
 */
public class Session extends UnicastRemoteObject implements ISession
{
    /**
     *
     */
    protected transient int m_PlayerColor;
    /**
     *
     */
    protected transient int m_PlayerId;
    /**
     *
     */
    protected transient IGame m_Game;
    /**
     *
     */
    protected transient String m_Username;
    /**
     *
     */
    protected transient int m_PlaatsbareLegers;
    /**
     *
     */
    protected transient int m_AvailableArmies;
    /**
     *
     */
    protected transient int m_AvailableBonusArmies;
    
    /**
     *
     * @param armies
     * @param bonusArmies
     */
    public void setAvailableArmies(int armies, int bonusArmies)
    {
	m_AvailableArmies = armies;
	m_AvailableBonusArmies = bonusArmies;
        System.out.println(m_Username + " legers " + m_AvailableArmies);
    }
    
    /**
     *
     * @return
     */
    public int getAvailableArmies()
    {
	return m_AvailableArmies;
    }
    
    /**
     *
     * @return
     */
    public int getAvailableBonusArmies()
    {
	return m_AvailableBonusArmies;
    }
    
    /**
     * Maakt een nieuw sessie-object aan met behulp van een Account. 
     *
     * @param username username van een specifieke speler
     * @param game geselecteerde game
     * @param color
     * @throws RemoteException
     */
    public Session(String username, IGame game, int color) throws RemoteException
    {
        m_Game = game;
        m_Username = username;
        m_PlayerColor = color;
    }

    /**
     * Geeft de spelerID terug van de speler dat gekoppeld is aan
     * het huidige spel.
     * Dit nummer geeft aan wanneer hij aan de beurt is.
     * getPlayerId: Opvragen van de ingame spelerID.
     * @return spelerID
     * @throws RemoteException
     */
    public int getPlayerId() throws RemoteException
    {
        return m_PlayerId;
    }
    
    /**
     *
     * @return
     * @throws RemoteException
     */
    public int getPlayerColor() throws RemoteException
    {
        return m_PlayerColor;
    }

    /**
     * Gereserveerd voor als een speler aangeeft dat hij klaar is 
     * met zijn beurt. (Deze functie kan nog vervallen).
     * @return 
     * @throws RemoteException
     */
    public int endTurn() throws RemoteException
    {
        try
        { 
            int result = m_Game.changeTurn(this);
	    m_Decission = TurnDecission.Undecided;
	    return result;
        }
        catch (Exception ex)
        {
            ex.printStackTrace();
	    return ErrorCodes.ERROR_UNKNOWN;
        }
    }

    /**
     * Speler verlaat hiermee het huidige spel.
     * @throws RemoteException
     * @throws Exception
     */
    public void leaveGame() throws RemoteException, Exception
    {
        // Deze functie bestaat nog niet, maar zal 
        // er zo uit komen zien.
        m_Game.leave(this);
    }

    /**
     * Geeft de spelernaam terug
     * @return spelernaam
     * @throws RemoteException 
     */
   public String getName() throws RemoteException
   {
        return m_Username;
   }

   /**
    *
    * @return
    * @throws RemoteException
    * @throws Exception
    */
   public boolean startGame() throws RemoteException, Exception
   {
        return m_Game.start(this);
   }

   /**
    *
    * @return
    * @throws RemoteException
    * @throws Exception
    */
   public List<IPlayer> getPlayers() throws RemoteException, Exception
   {
        return m_Game.getPlayers();
   }
   
   /**
    *
    * @param value
    */
   public void setPlayerId(int value)
   {
       m_PlayerId = value;
   }
   
   /**
    *
    * @return
    */
   public int getNumberPlaceableArmys()
   {
        return m_PlaatsbareLegers;
   }

    // Acties:
   /**
    *
    * @param land
    * @throws RemoteException
    */
   public void legerPlaatsen(Land land) throws RemoteException
   {
       //TODO: MAG NIET HIER, MOET IN GAME
       //TODO: missen heeeeeeeeeeeeeeeeeeeel veel constraints!!
       // controle of land een eigenland is
       if (land.getOwner() == this)
       {
	    land.setArmies(land.getArmies() + 1);
       }
    }

    /**
     *
     * @param landID1
     * @param amount
     * @param landID2
     * @return
     * @throws RemoteException
     * @throws Exception
     */
    public int attack(int landID1, int landID2, int amount) throws RemoteException, Exception
    {
        // geeft waarde true als aanval geldig is.
        return m_Game.attack(this, landID1, landID2, amount);
    }

/**
public int callbackaantalverdediging(ISession speler){
    int aantal = 0;
     Map<ISession,IPnlClientWorldMap> callbacks = ((Game)m_Game).getCallbacks();
            Iterator<Entry<ISession,IPnlClientWorldMap>> it = callbacks.entrySet().iterator();
        while (it.hasNext())
    {
            try {
                ISession session = it.next().getKey();
                IPnlClientWorldMap map = it.next().getValue();
                if (session.getName().equals(speler.getName())) {
                    aantal = map.getAantalVerdedigingsDobbelstenen(); // een willekeurige functie in PnlClientWorldMap (deze bestaat niet, maar is als voorbeeld) <-- callback
                    break; // <-- belangrijk!!!! deze zorgt ervoor dat je uit de 'while' gaat (omdat: je stuurt maar naar 1 en je hebt'm gevonden, je hoeft niet veder door de Map te gaan)
                }
            } catch (RemoteException ex) {
                ex.printStackTrace();
            }
  }
    return aantal;
}
*/
           // Beurt:
        // - bonus legers van kaarten en continenten mogen wel geplaatst worden als iemand wil aanvallen
        // - legers versterken (nieuwe legers plaatsen) of aanvallen
        //
        // if (aanvallen)
        // {
        // while (aanvallen) <-- LOOP (tot speler dit niet meer wil of kan)
        // {
        //  kies aantal legers aanvallen  (1 tot eigenland; dus max. eigenland - 1)
        //  kies aantal legers verdediger (1 of 2)
        //  computer dobbelt voor aanvaller  (automatisch, elk leger = 1 steen, max 3 dobbelstenen)
        //  computer dobbelt voor verdediger (automatisch, max. 2 legers verdedingen, elk leger = 1 steen)
        //  bekijk de verliezen, deze uidaten bij aanvaller of verdediger
        //  if (verdedigendland.legers.count == 0)
        //   verplaatsen(aanvallendland, verdedigendland, aantalLegers_aanvaller);
        //  hij mag altijd kiezen om weer aan te vallen (zelfs vanuit het gewonnen land)
        //  }
        //
        // if (kijk of er een land veroverd is == waar)
        // {
        //  speler krijgt kaart
        // }
        //
        // //speler mag 1x max. 7 legers verplaatsen naar een ander eigen land (moeten wel aan elkaar grenzen -> gekozenland.aangrenzendeLanden)
        // //FUTURE: LET OP DEZE ZIN VALT OP VERSCHILLENDE MANIEREN TE INTERPRETEREN
        // }
        // else //dus: legers plaatsen
        // {
        // int aantal_te_plaatsen = getNumberPlaceableArmys();
        // aantal_te_plaatsen x mag de speler op eigen landen klikken
        // }

    protected int m_Decission = TurnDecission.Undecided;
    /**
     *
     * @param decission
     * @return
     * @throws RemoteException
     * @throws Exception
     */
    public int turnDecission(int decission) throws RemoteException, Exception
    {
	switch (m_Decission)
	{
	    case TurnDecission.Undecided:
		m_Decission = decission;
		// Notify other Clients
		return m_Game.turnDecission(this, decission);
	    case TurnDecission.ReinforceBonus:
                
		if (decission == TurnDecission.Attack)
		{
		    m_Decission = decission;
		    // Notify other Clients
		    return m_Game.turnDecission(this, decission);
		}
                
		return ErrorCodes.ERROR_YOU_ALREADY_DECIDED;
	    default:
                
		return ErrorCodes.ERROR_YOU_ALREADY_DECIDED;
	}
    }
    
    public int reinforce(int landID, int amount) throws RemoteException, Exception
    {
        if (m_Decission == TurnDecission.Reinforce ||m_Decission == TurnDecission.ReinforceBonus || ((Game)m_Game).getState() == GameState.GAME_SETUP)
	    return m_Game.reinforce(this, landID, amount);
	return ErrorCodes.ERROR_REINFORCEMENTS_NOT_ALLOWED;
    }
 
    /**
     *
     * @param amount
     * @return
     * @throws RemoteException
     * @throws Exception
     */
    public int defend(int amount) throws RemoteException, Exception
    {
	return m_Game.defend(this, amount);
    }
}
